Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure GetCSRF doesn't return an empty token #32130

Merged
merged 11 commits into from
Sep 30, 2024

Conversation

wolfogre
Copy link
Member

Since page templates keep changing, some pages that contained forms with CSRF token no longer have them.

It leads to some calls of GetCSRF returning an empty string, which fails the tests. Like

// this test is not right because it just doesn't pass the CSRF validation
createAttachment(t, session, "user2/repo1", "image.png", generateImg(), http.StatusBadRequest)

The test did try to get the CSRF token and provided it, but it was empty.

@wolfogre wolfogre added type/testing skip-changelog This PR is irrelevant for the (next) changelog, for example bug fixes for unreleased features. labels Sep 25, 2024
@wolfogre wolfogre added this to the 1.23.0 milestone Sep 25, 2024
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Sep 25, 2024
@pull-request-size pull-request-size bot added the size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. label Sep 25, 2024
@github-actions github-actions bot added the modifies/go Pull requests that update Go code label Sep 25, 2024
@wolfogre
Copy link
Member Author

wolfogre commented Sep 25, 2024

Not yet completed, I want to see CICD fail first, then succeed with new commits.

@pull-request-size pull-request-size bot added size/S Denotes a PR that changes 10-29 lines, ignoring generated files. and removed size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. labels Sep 25, 2024
@wolfogre wolfogre marked this pull request as ready for review September 25, 2024 07:31
@wolfogre
Copy link
Member Author

I believe it's worth being backported to follow #32069.

@wolfogre wolfogre added the backport/v1.22 This PR should be backported to Gitea 1.22 label Sep 25, 2024
@wxiaoguang
Copy link
Contributor

wxiaoguang commented Sep 25, 2024

I do not think this change is right.

The problem is that TestCreateAnonymousAttachment should use an "anonymous" csrf token to test the "anonymous" request.

Hmm ... I see the "anonymous" crsf token is provided by "user/login" now ....

@wolfogre
Copy link
Member Author

wolfogre commented Sep 25, 2024

I have a new idea to improve it, maybe after this PR.

Since it doesn't matter where the test code gets the CSRF token to send requests, why not

-func GetCSRF(t testing.TB, session *TestSession, urlStr string) string
+func GetCSRF(t testing.TB, session *TestSession) string {
	// try "/user/login" to get token
	// if it returns `SeeOther`, so it's logged in, try "/user/settings" again
}

/user/login and /user/settings pages should be stable enough, and developers don't need to decide which URL to get the token any longer.

@wxiaoguang
Copy link
Contributor

I have a new idea to improve it, maybe after this PR.

Since it doesn't matter where the test code gets the CSRF token to send requests, why not

That's not the initial idea of Gitea's CSRF token design, see this:

image

Ideally, the CSRF token was designed to be related to current page (even the current form/action), but nobody did so.

@wolfogre
Copy link
Member Author

Ideally, the CSRF token was designed to be related to current page (even the current form/action), but nobody did so.

Oh, thanks, I understand now.

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Sep 25, 2024
@@ -59,15 +57,14 @@ func createAttachment(t *testing.T, session *TestSession, repoURL, filename stri
func TestCreateAnonymousAttachment(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := emptyTestSession(t)
// this test is not right because it just doesn't pass the CSRF validation
createAttachment(t, session, "user2/repo1", "image.png", generateImg(), http.StatusBadRequest)
createAttachment(t, session, GetCSRF(t, session, "/user/login"), "user2/repo1", "image.png", generateImg(), http.StatusSeeOther)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if someone looking at this code in two months knows why an attachment test calls a login endpoint...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reads as this: when TestCreateAnonymousAttachment, it needs to GetCSRF from /user/login, it sounds reasonable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the CSRF token is not action related why can't we have a GetCSRF method without passed url? If /user/login is a redirect call /user/settings. One of both requests contains a token.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is user-related.

And I guess just no one has interest to work on #32130 (comment) , and no one has the explicitly said that "that FIXME could be removed and Gitea will always use a common CSRF token for current user"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what @KN4CK3R wants to say is we should document exactly that with a comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's user-related, that's the reason why there is the session.

func GetCSRF(t testing.TB, session *TestSession) string {
	t.Helper()
	
	req := NewRequest(t, "GET", "/user/login")
	resp := session.MakeRequest(t, req, NoExpectedStatus)
	
	if resp.Code == http.StatusSeeOther {
		req = NewRequest(t, "GET", "/user/settings")
		resp = session.MakeRequest(t, req, http.StatusOk)
	}
	
	doc := NewHTMLParser(t, resp.Body)
	return doc.GetCSRF()
}

If we decide to use action-related CSRF tokens the GetCSRF method with an url must change too because then a single page can contain multiple forms with different tokens but doc.GetCSRF() currently just returns the first token.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would slow down many tests by using the extra request.

In most cases, the test writer clearly knows what CSRF token they would like to use: anonymous, or a signed-in user.

If you prefer to do so, I think it needs 2 functions:

GetCSRFForAnonymous
GetCSRFForCurrentUser

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(while these improvements could be in a separate PR but not in this PR's scope)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KN4CK3R

a separate PR
-> Refactor CSRF token #32216

@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Sep 25, 2024
@lunny lunny added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Sep 28, 2024
@lunny lunny enabled auto-merge (squash) September 30, 2024 01:59
@lunny lunny merged commit 1328387 into go-gitea:main Sep 30, 2024
26 checks passed
GiteaBot pushed a commit to GiteaBot/gitea that referenced this pull request Sep 30, 2024
Since page templates keep changing, some pages that contained forms with
CSRF token no longer have them.

It leads to some calls of `GetCSRF` returning an empty string, which
fails the tests. Like

https://github.com/go-gitea/gitea/blob/3269b04d61ffe6a7ce462cd05ee150e4491124e8/tests/integration/attachment_test.go#L62-L63

The test did try to get the CSRF token and provided it, but it was
empty.
@GiteaBot GiteaBot added backport/done All backports for this PR have been created and removed reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. labels Sep 30, 2024
yp05327 pushed a commit that referenced this pull request Oct 1, 2024
Backport #32130 by @wolfogre

Since page templates keep changing, some pages that contained forms with
CSRF token no longer have them.

It leads to some calls of `GetCSRF` returning an empty string, which
fails the tests. Like


https://github.com/go-gitea/gitea/blob/3269b04d61ffe6a7ce462cd05ee150e4491124e8/tests/integration/attachment_test.go#L62-L63

The test did try to get the CSRF token and provided it, but it was
empty.

Co-authored-by: Jason Song <i@wolfogre.com>
zjjhot added a commit to zjjhot/gitea that referenced this pull request Oct 2, 2024
* giteaofficial/main:
  Fix javascript error when an anonymous user visiting migration page (go-gitea#32144)
  Make oauth2 code clear. Move oauth2 provider code to their own packages/files (go-gitea#32148)
  Support repo license (go-gitea#24872)
  Fix the logic of finding the latest pull review commit ID (go-gitea#32139)
  Ensure `GetCSRF` doesn't return an empty token (go-gitea#32130)
  Bump minio-go to latest version (go-gitea#32156)
@wxiaoguang wxiaoguang mentioned this pull request Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/done All backports for this PR have been created backport/v1.22 This PR should be backported to Gitea 1.22 lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. modifies/go Pull requests that update Go code size/S Denotes a PR that changes 10-29 lines, ignoring generated files. skip-changelog This PR is irrelevant for the (next) changelog, for example bug fixes for unreleased features. type/testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants